* convert kml to Format class.
* update dependencies.
* restore kml real time postion writer functionality.
and have it produce valid kml.
Add a test case.
* correct new kml test reference file name.
jeeps/gpsusbcommon.h
jeeps/gpsusbint.h
jeeps/gpsutil.h
+ kml.h
legacyformat.h
lowranceusr.h
magellan.h
jeeps/gpsusbcommon.h \
jeeps/gpsusbint.h \
jeeps/gpsutil.h \
+ kml.h \
legacyformat.h \
lowranceusr.h \
magellan.h \
swapdata.h trackfilter.h transform.h validate.h gbversion.h vecs.h \
format.h energympro.h garmin_fit.h geojson.h src/core/file.h ggv_bin.h \
globalsat_sport.h gpx.h src/core/xmlstreamwriter.h src/core/xmltag.h \
- legacyformat.h lowranceusr.h mynav.h qstarz_bl_1000.h nmea.h random.h \
- shape.h shapelib/shapefil.h subrip.h xcsv.h garmin_fs.h jeeps/gps.h \
- jeeps/../defs.h jeeps/gpsport.h jeeps/gpsdevice.h jeeps/gpssend.h \
- jeeps/gpsread.h jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h \
- jeeps/gpscom.h jeeps/gpsfmt.h jeeps/gpsmath.h jeeps/gpsmem.h \
- jeeps/gpsrqst.h src/core/textstream.h yahoo.h xmlgeneric.h
+ kml.h xmlgeneric.h legacyformat.h lowranceusr.h mynav.h nmea.h \
+ qstarz_bl_1000.h random.h shape.h shapelib/shapefil.h subrip.h xcsv.h \
+ garmin_fs.h jeeps/gps.h jeeps/../defs.h jeeps/gpsport.h \
+ jeeps/gpsdevice.h jeeps/gpssend.h jeeps/gpsread.h jeeps/gpsutil.h \
+ jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \
+ jeeps/gpsmath.h jeeps/gpsmem.h jeeps/gpsrqst.h src/core/textstream.h \
+ yahoo.h
formspec.o: formspec.cc defs.h config.h zlib/zlib.h zlib/zconf.h \
formspec.h inifile.h gbfile.h session.h src/core/datetime.h \
src/core/optional.h
jeeps/gpsrqst.h garmin_tables.h grtcirc.h jeeps/gpsserial.h vecs.h \
energympro.h garmin_fit.h geojson.h src/core/file.h ggv_bin.h \
globalsat_sport.h gpx.h src/core/xmlstreamwriter.h src/core/xmltag.h \
- legacyformat.h lowranceusr.h mynav.h qstarz_bl_1000.h nmea.h random.h \
- shape.h shapelib/shapefil.h subrip.h xcsv.h src/core/textstream.h \
- yahoo.h xmlgeneric.h
+ kml.h xmlgeneric.h legacyformat.h lowranceusr.h mynav.h nmea.h \
+ qstarz_bl_1000.h random.h shape.h shapelib/shapefil.h subrip.h xcsv.h \
+ src/core/textstream.h yahoo.h
garmin_device_xml.o: garmin_device_xml.cc defs.h config.h zlib/zlib.h \
zlib/zconf.h formspec.h inifile.h gbfile.h session.h \
src/core/datetime.h src/core/optional.h garmin_device_xml.h \
csv_util.h nmea.h format.h
kml.o: kml.cc defs.h config.h zlib/zlib.h zlib/zconf.h formspec.h \
inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h \
- grtcirc.h src/core/file.h src/core/logging.h \
- src/core/xmlstreamwriter.h src/core/xmltag.h units.h xmlgeneric.h
+ kml.h format.h src/core/file.h src/core/xmlstreamwriter.h xmlgeneric.h \
+ grtcirc.h src/core/logging.h src/core/xmltag.h units.h
lmx.o: lmx.cc defs.h config.h zlib/zlib.h zlib/zconf.h formspec.h \
inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h \
xmlgeneric.h
src/core/optional.h explorist_ini.h format.h gbser.h magellan.h vecs.h \
energympro.h garmin_fit.h geojson.h src/core/file.h ggv_bin.h \
globalsat_sport.h gpx.h src/core/xmlstreamwriter.h src/core/xmltag.h \
- legacyformat.h lowranceusr.h mynav.h qstarz_bl_1000.h nmea.h random.h \
- shape.h shapelib/shapefil.h subrip.h xcsv.h garmin_fs.h jeeps/gps.h \
- jeeps/../defs.h jeeps/gpsport.h jeeps/gpsdevice.h jeeps/gpssend.h \
- jeeps/gpsread.h jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h \
- jeeps/gpscom.h jeeps/gpsfmt.h jeeps/gpsmath.h jeeps/gpsmem.h \
- jeeps/gpsrqst.h src/core/textstream.h yahoo.h xmlgeneric.h
+ kml.h xmlgeneric.h legacyformat.h lowranceusr.h mynav.h nmea.h \
+ qstarz_bl_1000.h random.h shape.h shapelib/shapefil.h subrip.h xcsv.h \
+ garmin_fs.h jeeps/gps.h jeeps/../defs.h jeeps/gpsport.h \
+ jeeps/gpsdevice.h jeeps/gpssend.h jeeps/gpsread.h jeeps/gpsutil.h \
+ jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \
+ jeeps/gpsmath.h jeeps/gpsmem.h jeeps/gpsrqst.h src/core/textstream.h \
+ yahoo.h
main.o: main.cc defs.h config.h zlib/zlib.h zlib/zconf.h formspec.h \
inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h \
cet_util.h csv_util.h filter.h filter_vecs.h arcdist.h bend.h \
stackfilter.h swapdata.h trackfilter.h transform.h validate.h format.h \
src/core/file.h src/core/usasciicodec.h vecs.h energympro.h \
garmin_fit.h geojson.h ggv_bin.h globalsat_sport.h gpx.h \
- src/core/xmlstreamwriter.h src/core/xmltag.h legacyformat.h \
- lowranceusr.h mynav.h qstarz_bl_1000.h nmea.h random.h shape.h \
- shapelib/shapefil.h subrip.h xcsv.h garmin_fs.h jeeps/gps.h \
+ src/core/xmlstreamwriter.h src/core/xmltag.h kml.h xmlgeneric.h \
+ legacyformat.h lowranceusr.h mynav.h nmea.h qstarz_bl_1000.h random.h \
+ shape.h shapelib/shapefil.h subrip.h xcsv.h garmin_fs.h jeeps/gps.h \
jeeps/../defs.h jeeps/gpsport.h jeeps/gpsdevice.h jeeps/gpssend.h \
jeeps/gpsread.h jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h \
jeeps/gpscom.h jeeps/gpsfmt.h jeeps/gpsmath.h jeeps/gpsmem.h \
- jeeps/gpsrqst.h src/core/textstream.h yahoo.h xmlgeneric.h
+ jeeps/gpsrqst.h src/core/textstream.h yahoo.h
mapasia.o: mapasia.cc defs.h config.h zlib/zlib.h zlib/zconf.h formspec.h \
inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h
mapbar_track.o: mapbar_track.cc defs.h config.h zlib/zlib.h zlib/zconf.h \
src/core/logging.h
stmwpp.o: stmwpp.cc defs.h config.h zlib/zlib.h zlib/zconf.h formspec.h \
inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h \
- csv_util.h cet_util.h
+ cet_util.h csv_util.h
strptime.o: strptime.c config.h strptime.h
subrip.o: subrip.cc defs.h config.h zlib/zlib.h zlib/zconf.h formspec.h \
inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h \
inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h \
vecs.h format.h energympro.h garmin_fit.h geojson.h src/core/file.h \
ggv_bin.h globalsat_sport.h gpx.h src/core/xmlstreamwriter.h \
- src/core/xmltag.h legacyformat.h lowranceusr.h mynav.h \
- qstarz_bl_1000.h nmea.h random.h shape.h shapelib/shapefil.h subrip.h \
- xcsv.h garmin_fs.h jeeps/gps.h jeeps/../defs.h jeeps/gpsport.h \
- jeeps/gpsdevice.h jeeps/gpssend.h jeeps/gpsread.h jeeps/gpsutil.h \
- jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \
- jeeps/gpsmath.h jeeps/gpsmem.h jeeps/gpsrqst.h src/core/textstream.h \
- yahoo.h xmlgeneric.h gbversion.h src/core/logging.h
+ src/core/xmltag.h kml.h xmlgeneric.h legacyformat.h lowranceusr.h \
+ mynav.h nmea.h qstarz_bl_1000.h random.h shape.h shapelib/shapefil.h \
+ subrip.h xcsv.h garmin_fs.h jeeps/gps.h jeeps/../defs.h \
+ jeeps/gpsport.h jeeps/gpsdevice.h jeeps/gpssend.h jeeps/gpsread.h \
+ jeeps/gpsutil.h jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h \
+ jeeps/gpsfmt.h jeeps/gpsmath.h jeeps/gpsmem.h jeeps/gpsrqst.h \
+ src/core/textstream.h yahoo.h gbversion.h src/core/logging.h
vidaone.o: vidaone.cc defs.h config.h zlib/zlib.h zlib/zconf.h formspec.h \
inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h
vitosmt.o: vitosmt.cc defs.h config.h zlib/zlib.h zlib/zconf.h formspec.h \
#include <QtCore/QtGlobal> // for foreach, qint64, qPrintable
#include "defs.h"
+#include "kml.h"
#include "formspec.h" // for FsChainFind, kFsGpx
#include "grtcirc.h" // for RAD, gcdist, radtometers
#include "src/core/datetime.h" // for DateTime
#include "xmlgeneric.h" // for cb_cdata, cb_end, cb_start, xg_callback, xg_string, xg_cb_type, xml_deinit, xml_ignore_tags, xml_init, xml_read, xg_tag_mapping
-// options
-static char* opt_deficon = nullptr;
-static char* opt_export_lines = nullptr;
-static char* opt_export_points = nullptr;
-static char* opt_export_track = nullptr;
-static char* opt_line_width = nullptr;
-static char* opt_line_color = nullptr;
-static char* opt_floating = nullptr;
-static char* opt_extrude = nullptr;
-static char* opt_trackdata = nullptr;
-static char* opt_trackdirection = nullptr;
-static char* opt_units = nullptr;
-static char* opt_labels = nullptr;
-static char* opt_max_position_points = nullptr;
-static char* opt_rotate_colors = nullptr;
-static char* opt_precision = nullptr;
-
-static int export_lines;
-static int export_points;
-static int export_track;
-static int floating;
-static int extrude;
-static int trackdata;
-static int trackdirection;
-static int max_position_points;
-static int rotate_colors;
-static int line_width;
-static int html_encrypt;
-static int precision;
-
-static Waypoint* wpt_tmp;
-static int wpt_tmp_queued;
-static QString posnfilename;
-static QString posnfilenametmp;
-
-static route_head* gx_trk_head;
-static QList<gpsbabel::DateTime>* gx_trk_times;
-static QList<std::tuple<int, double, double, double>>* gx_trk_coords;
-
-static gpsbabel::File* oqfile;
-static gpsbabel::XmlStreamWriter* writer;
-
-enum kml_point_type {
- kmlpt_unknown,
- kmlpt_waypoint,
- kmlpt_track,
- kmlpt_route,
- kmlpt_multitrack,
- kmlpt_other
-};
-
-static int realtime_positioning;
-static bounds kml_bounds;
-static gpsbabel::DateTime kml_time_max;
-static gpsbabel::DateTime kml_time_min;
-
-#define DEFAULT_PRECISION "6"
-
// Icons provided and hosted by Google. Used with permission.
#define ICON_BASE "https://earth.google.com/images/kml-icons/"
-
-// Multitrack ids to correlate Schema to SchemaData
-static const char kmt_heartrate[] = "heartrate";
-static const char kmt_cadence[] = "cadence";
-static const char kmt_temperature[] = "temperature";
-static const char kmt_depth[] = "depth";
-static const char kmt_power[] = "power";
-
-
-static
-QVector<arglist_t> kml_args = {
- {"deficon", &opt_deficon, "Default icon name", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr },
- {
- "lines", &opt_export_lines,
- "Export linestrings for tracks and routes",
- "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr,
- },
- {
- "points", &opt_export_points,
- "Export placemarks for tracks and routes",
- "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "line_width", &opt_line_width,
- "Width of lines, in pixels",
- "6", ARGTYPE_INT, ARG_NOMINMAX, nullptr
- },
- {
- "line_color", &opt_line_color,
- "Line color, specified in hex AABBGGRR",
- "99ffac59", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
- },
- {
- "floating", &opt_floating,
- "Altitudes are absolute and not clamped to ground",
- "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "extrude", &opt_extrude,
- "Draw extrusion line from trackpoint to ground",
- "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "track", &opt_export_track,
- "Write KML track (default = 0)",
- "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "trackdata", &opt_trackdata,
- "Include extended data for trackpoints (default = 1)",
- "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "trackdirection", &opt_trackdirection,
- "Indicate direction of travel in track icons (default = 0)",
- "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "units", &opt_units,
- "Units used when writing comments ('s'tatute, 'm'etric,' 'n'autical, 'a'viation)",
- "s", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
- },
- {
- "labels", &opt_labels,
- "Display labels on track and routepoints (default = 1)",
- "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "max_position_points", &opt_max_position_points,
- "Retain at most this number of position points (0 = unlimited)",
- "0", ARGTYPE_INT, ARG_NOMINMAX, nullptr
- },
- {
- "rotate_colors", &opt_rotate_colors,
- "Rotate colors for tracks and routes (default automatic)",
- nullptr, ARGTYPE_FLOAT, "0", "360", nullptr
- },
- {
- "prec", &opt_precision,
- "Precision of coordinates, number of decimals",
- DEFAULT_PRECISION, ARGTYPE_INT, ARG_NOMINMAX, nullptr
- },
-};
-
-static
-struct {
- int freshness;
- const char* icon;
-} kml_tracking_icons[] = {
- { 60, ICON_BASE "youarehere-60.png" }, // Red
- { 30, ICON_BASE "youarehere-30.png" }, // Yellow
- { 0, ICON_BASE "youarehere-0.png" }, // Green
-};
-
#define ICON_NOSAT ICON_BASE "youarehere-warning.png"
#define ICON_WPT "https://maps.google.com/mapfiles/kml/pal4/icon61.png"
#define ICON_TRK ICON_BASE "track-directional/track-none.png"
#define ICON_MULTI_TRK ICON_BASE "track-directional/track-0.png"
#define ICON_DIR ICON_BASE "track-directional/track-%1.png" // format string where next arg is rotational degrees.
-static struct {
- float seq{0.0f};
- float step{0.0f};
- gb_color color;
-} kml_color_sequencer;
-#define KML_COLOR_LIMIT 204 /* allowed range [0,255] */
-
#define MYNAME "kml"
-static void kml_init_color_sequencer(unsigned int steps_per_rev)
+void KmlFormat::kml_init_color_sequencer(unsigned int steps_per_rev)
{
if (rotate_colors) {
float color_step = atof(opt_rotate_colors);
if (color_step > 0.0f) {
// step around circle by given number of degrees for each track(route)
- kml_color_sequencer.step = ((float)KML_COLOR_LIMIT) * 6.0f * color_step / 360.0f;
+ kml_color_sequencer.step = ((float)kml_color_limit) * 6.0f * color_step / 360.0f;
} else {
// one cycle around circle for all the tracks(routes)
- kml_color_sequencer.step = ((float)KML_COLOR_LIMIT) * 6.0f / ((float)steps_per_rev);
+ kml_color_sequencer.step = ((float)kml_color_limit) * 6.0f / ((float)steps_per_rev);
}
kml_color_sequencer.color.opacity=255;
kml_color_sequencer.seq = 0.0f;
}
}
-static void kml_step_color()
+void KmlFormat::kml_step_color()
{
- // Map kml_color_sequencer.seq to an integer in the range [0, KML_COLOR_LIMIT*6).
+ // Map kml_color_sequencer.seq to an integer in the range [0, kml_color_limit*6).
// Note that color_seq may be outside this range if the cast from float to int fails.
- int color_seq = ((int) kml_color_sequencer.seq) % (KML_COLOR_LIMIT * 6);
+ int color_seq = ((int) kml_color_sequencer.seq) % (kml_color_limit * 6);
if (global_opts.debug_level >= 1) {
printf(MYNAME ": kml_color_sequencer seq %f %d, step %f\n",kml_color_sequencer.seq, color_seq, kml_color_sequencer.step);
}
- if ((color_seq >= (0*KML_COLOR_LIMIT)) && (color_seq < (1*KML_COLOR_LIMIT))) {
- kml_color_sequencer.color.bbggrr = (0)<<16 | (color_seq)<<8 | (KML_COLOR_LIMIT);
- } else if ((color_seq >= (1*KML_COLOR_LIMIT)) && (color_seq < (2*KML_COLOR_LIMIT))) {
- kml_color_sequencer.color.bbggrr = (0)<<16 | (KML_COLOR_LIMIT)<<8 | (2*KML_COLOR_LIMIT-color_seq);
- } else if ((color_seq >= (2*KML_COLOR_LIMIT)) && (color_seq < (3*KML_COLOR_LIMIT))) {
- kml_color_sequencer.color.bbggrr = (color_seq-2*KML_COLOR_LIMIT)<<16 | (KML_COLOR_LIMIT)<<8 | (0);
- } else if ((color_seq >= (3*KML_COLOR_LIMIT)) && (color_seq < (4*KML_COLOR_LIMIT))) {
- kml_color_sequencer.color.bbggrr = (KML_COLOR_LIMIT)<<16 | (4*KML_COLOR_LIMIT-color_seq)<<8 | (0);
- } else if ((color_seq >= (4*KML_COLOR_LIMIT)) && (color_seq < (5*KML_COLOR_LIMIT))) {
- kml_color_sequencer.color.bbggrr = (KML_COLOR_LIMIT)<<16 | (0)<<8 | (color_seq-4*KML_COLOR_LIMIT);
- } else if ((color_seq >= (5*KML_COLOR_LIMIT)) && (color_seq < (6*KML_COLOR_LIMIT))) {
- kml_color_sequencer.color.bbggrr = (6*KML_COLOR_LIMIT-color_seq)<<16 | (0)<<8 | (KML_COLOR_LIMIT);
+ if ((color_seq >= (0*kml_color_limit)) && (color_seq < (1*kml_color_limit))) {
+ kml_color_sequencer.color.bbggrr = (0)<<16 | (color_seq)<<8 | (kml_color_limit);
+ } else if ((color_seq >= (1*kml_color_limit)) && (color_seq < (2*kml_color_limit))) {
+ kml_color_sequencer.color.bbggrr = (0)<<16 | (kml_color_limit)<<8 | (2*kml_color_limit-color_seq);
+ } else if ((color_seq >= (2*kml_color_limit)) && (color_seq < (3*kml_color_limit))) {
+ kml_color_sequencer.color.bbggrr = (color_seq-2*kml_color_limit)<<16 | (kml_color_limit)<<8 | (0);
+ } else if ((color_seq >= (3*kml_color_limit)) && (color_seq < (4*kml_color_limit))) {
+ kml_color_sequencer.color.bbggrr = (kml_color_limit)<<16 | (4*kml_color_limit-color_seq)<<8 | (0);
+ } else if ((color_seq >= (4*kml_color_limit)) && (color_seq < (5*kml_color_limit))) {
+ kml_color_sequencer.color.bbggrr = (kml_color_limit)<<16 | (0)<<8 | (color_seq-4*kml_color_limit);
+ } else if ((color_seq >= (5*kml_color_limit)) && (color_seq < (6*kml_color_limit))) {
+ kml_color_sequencer.color.bbggrr = (6*kml_color_limit-color_seq)<<16 | (0)<<8 | (kml_color_limit);
} else { // should not occur, but to be safe generate a legal color.
warning(MYNAME ": Error in color conversion - using default color.\n");
kml_color_sequencer.color.bbggrr = (102)<<16 | (102)<<8 | (102);
kml_color_sequencer.seq = kml_color_sequencer.seq + kml_color_sequencer.step;
}
-static xg_callback wpt_s, wpt_e;
-static xg_callback wpt_name, wpt_desc, wpt_coord, wpt_icon, trk_coord, wpt_time, wpt_ts_begin, wpt_ts_end;
-static xg_callback gx_trk_s, gx_trk_e;
-static xg_callback gx_trk_when, gx_trk_coord;
-
-static
-xg_tag_mapping kml_map[] = {
- { wpt_s, cb_start, "/Placemark" },
- { wpt_e, cb_end, "/Placemark" },
- { wpt_name, cb_cdata, "/Placemark/name" },
- { wpt_desc, cb_cdata, "/Placemark/description" },
- { wpt_ts_begin, cb_cdata, "/Placemark/TimeSpan/begin" },
- { wpt_ts_end, cb_cdata, "/Placemark/TimeSpan/end" },
- { wpt_time, cb_cdata, "/Placemark/TimeStamp/when" },
- // Alias for above used in KML 2.0
- { wpt_time, cb_cdata, "/Placemark/TimeInstant/timePosition" },
- { wpt_coord, cb_cdata, "/Placemark/Point/coordinates" },
- { wpt_icon, cb_cdata, "/Placemark/Style/Icon/href" },
- { trk_coord, cb_cdata, "/Placemark/MultiGeometry/LineString/coordinates" },
- { trk_coord, cb_cdata, "/Placemark/GeometryCollection/LineString/coordinates" },
- { trk_coord, cb_cdata, "/Placemark/Polygon/outerBoundaryIs/LinearRing/coordinates" },
- { trk_coord, cb_cdata, "/Placemark/LineString/coordinates" },
- { gx_trk_s, cb_start, "/Placemark/*gx:Track" },
- { gx_trk_e, cb_end, "/Placemark/*gx:Track" },
- { gx_trk_when, cb_cdata, "/Placemark/*gx:Track/when" },
- { gx_trk_coord, cb_cdata, "/Placemark/*gx:Track/gx:coord" },
- { gx_trk_s, cb_start, "/Placemark/Track" }, // KML 2.3
- { gx_trk_e, cb_end, "/Placemark/Track" }, // KML 2.3
- { gx_trk_when, cb_cdata, "/Placemark/Track/when" }, // KML 2.3
- { gx_trk_coord, cb_cdata, "/Placemark/Track/coord" }, // KML 2.3
- { gx_trk_s, cb_start, "/Placemark/MultiTrack/Track" }, // KML 2.3
- { gx_trk_e, cb_end, "/Placemark/MultiTrack/Track" }, // KML 2.3
- { gx_trk_when, cb_cdata, "/Placemark/MultiTrack/Track/when" }, // KML 2.3
- { gx_trk_coord, cb_cdata, "/Placemark/MultiTrack/Track/coord" }, // KML 2.3
- { nullptr, (xg_cb_type) 0, nullptr }
-};
-
-static
-const char* kml_tags_to_ignore[] = {
+const char* KmlFormat::kml_tags_to_ignore[] = {
"kml",
"Document",
"Folder",
nullptr
};
-static
-const char* kml_tags_to_skip[] = {
+const char* KmlFormat::kml_tags_to_skip[] = {
"Camera",
"LookAt",
"styleUrl",
nullptr
};
-// The TimeSpan/begin and TimeSpan/end DateTimes:
-static gpsbabel::DateTime wpt_timespan_begin, wpt_timespan_end;
-
-void wpt_s(xg_string, const QXmlStreamAttributes*)
+void KmlFormat::wpt_s(xg_string /*args*/, const QXmlStreamAttributes* /*attrs*/)
{
if (wpt_tmp) {
fatal(MYNAME ": wpt_s: invalid kml file\n");
}
wpt_tmp = new Waypoint;
- wpt_tmp_queued = 0;
+ wpt_tmp_queued = false;
/* Invalidate timespan elements for a beginning Placemark,
* so that each Placemark has its own (or no) TimeSpan. */
wpt_timespan_end = gpsbabel::DateTime();
}
-void wpt_e(xg_string, const QXmlStreamAttributes*)
+void KmlFormat::wpt_e(xg_string /*args*/, const QXmlStreamAttributes* /*attrs*/)
{
if (!wpt_tmp) {
fatal(MYNAME ": wpt_e: invalid kml file\n");
delete wpt_tmp;
wpt_tmp = nullptr;
}
- wpt_tmp_queued = 0;
+ wpt_tmp_queued = false;
}
-void wpt_name(xg_string args, const QXmlStreamAttributes*)
+void KmlFormat::wpt_name(xg_string args, const QXmlStreamAttributes* /*attrs*/)
{
if (!wpt_tmp) {
fatal(MYNAME ": wpt_name: invalid kml file\n");
wpt_tmp->shortname = args;
}
-void wpt_desc(const QString& args, const QXmlStreamAttributes*)
+void KmlFormat::wpt_desc(const QString& args, const QXmlStreamAttributes* /*attrs*/)
{
if (!wpt_tmp) {
fatal(MYNAME ": wpt_desc: invalid kml file\n");
wpt_tmp->description += args.trimmed();
}
-void wpt_time(xg_string args, const QXmlStreamAttributes*)
+void KmlFormat::wpt_time(xg_string args, const QXmlStreamAttributes* /*attrs*/)
{
if (!wpt_tmp) {
fatal(MYNAME ": wpt_time: invalid kml file\n");
wpt_tmp->SetCreationTime(xml_parse_time(args));
}
-void wpt_ts_begin(xg_string args, const QXmlStreamAttributes*)
+void KmlFormat::wpt_ts_begin(xg_string args, const QXmlStreamAttributes* /*attrs*/)
{
wpt_timespan_begin = xml_parse_time(args);
}
-void wpt_ts_end(xg_string args, const QXmlStreamAttributes*)
+void KmlFormat::wpt_ts_end(xg_string args, const QXmlStreamAttributes* /*attrs*/)
{
wpt_timespan_end = xml_parse_time(args);
}
-void wpt_coord(const QString& args, const QXmlStreamAttributes*)
+void KmlFormat::wpt_coord(const QString& args, const QXmlStreamAttributes* /*attrs*/)
{
double lat, lon, alt;
if (! wpt_tmp) {
if (n == 3) {
wpt_tmp->altitude = alt;
}
- wpt_tmp_queued = 1;
+ wpt_tmp_queued = true;
}
-void wpt_icon(xg_string args, const QXmlStreamAttributes*)
+void KmlFormat::wpt_icon(xg_string args, const QXmlStreamAttributes* /*attrs*/)
{
if (wpt_tmp) {
wpt_tmp->icon_descr = args;
}
}
-void trk_coord(xg_string args, const QXmlStreamAttributes*)
+void KmlFormat::trk_coord(xg_string args, const QXmlStreamAttributes* /*attrs*/)
{
auto* trk_head = new route_head;
if (wpt_tmp && !wpt_tmp->shortname.isEmpty()) {
track_add_head(trk_head);
const auto vecs = args.simplified().split(' ');
- for(const auto& vec : vecs) {
+ for (const auto& vec : vecs) {
const QStringList coords = vec.split(',');
auto csize = coords.size();
- auto trkpt = new Waypoint;
+ auto* trkpt = new Waypoint;
if (csize == 3) {
trkpt->altitude = coords[2].toDouble();
}
}
-void gx_trk_s(xg_string, const QXmlStreamAttributes*)
+void KmlFormat::gx_trk_s(xg_string /*args*/, const QXmlStreamAttributes* /*attrs*/)
{
gx_trk_head = new route_head;
if (wpt_tmp && !wpt_tmp->shortname.isEmpty()) {
gx_trk_coords = new QList<std::tuple<int, double, double, double>>;
}
-void gx_trk_e(xg_string, const QXmlStreamAttributes*)
+void KmlFormat::gx_trk_e(xg_string /*args*/, const QXmlStreamAttributes* /*attrs*/)
{
// Check that for every temporal value (kml:when) in a kml:Track there is a position (kml:coord) value.
// Check that for every temporal value (kml:when) in a gx:Track there is a position (gx:coord) value.
gx_trk_coords = nullptr;
}
-void gx_trk_when(xg_string args, const QXmlStreamAttributes*)
+void KmlFormat::gx_trk_when(xg_string args, const QXmlStreamAttributes* /*attrs*/)
{
if (! gx_trk_times) {
fatal(MYNAME ": gx_trk_when: invalid kml file\n");
gx_trk_times->append(xml_parse_time(args));
}
-void gx_trk_coord(xg_string args, const QXmlStreamAttributes*)
+void KmlFormat::gx_trk_coord(xg_string args, const QXmlStreamAttributes* /*attrs*/)
{
if (! gx_trk_coords) {
fatal(MYNAME ": gx_trk_coord: invalid kml file\n");
gx_trk_coords->append(std::make_tuple(n, lat, lon, alt));
}
-static
-void
-kml_rd_init(const QString& fname)
+void KmlFormat::rd_init(const QString& fname)
{
- xml_init(fname, kml_map, nullptr, kml_tags_to_ignore, kml_tags_to_skip);
+ xml_init(fname, build_xg_tag_map(this, kml_map), nullptr, kml_tags_to_ignore, kml_tags_to_skip, true);
}
-static
-void
-kml_read()
+void KmlFormat::read()
{
xml_read();
}
-static void
-kml_rd_deinit()
+void KmlFormat::rd_deinit()
{
xml_deinit();
}
-static void
-kml_wr_init(const QString& fname)
+void KmlFormat::wr_init(const QString& fname)
{
char u = 's';
waypt_init_bounds(&kml_bounds);
* The magic here is to try to ensure that posnfilename is atomically
* updated.
*/
-static void
-kml_wr_position_init(const QString& fname)
+void KmlFormat::wr_position_init(const QString& fname)
{
posnfilename = fname;
posnfilenametmp = QString("%1-").arg(fname);
max_position_points = atoi(opt_max_position_points);
}
-static void
-kml_wr_deinit()
+void KmlFormat::wr_deinit()
{
writer->writeEndDocument();
delete writer;
}
}
-static void
-kml_wr_position_deinit()
+void KmlFormat::wr_position_deinit()
{
// kml_wr_deinit();
posnfilename.clear();
}
-static void
-kml_output_linestyle(char* /*color*/, int width)
+void KmlFormat::kml_output_linestyle(char* /*color*/, int width) const
{
// Style settings for line strings
writer->writeStartElement(QStringLiteral("LineStyle"));
}
-static void kml_write_bitmap_style_(const QString& style, const QString& bitmap,
- int highlighted, int force_heading)
+void KmlFormat::kml_write_bitmap_style_(const QString& style, const QString& bitmap,
+ int highlighted, int force_heading) const
{
int is_track = style.startsWith("track");
int is_multitrack = style.startsWith("multiTrack");
* and non-highlighted version of the style to allow the icons
* to magnify slightly on a rollover.
*/
-static void kml_write_bitmap_style(kml_point_type pt_type, const QString& bitmap,
- const QString& customstyle)
+void KmlFormat::kml_write_bitmap_style(kml_point_type pt_type, const QString& bitmap,
+ const QString& customstyle) const
{
int force_heading = 0;
QString style;
writer->writeEndElement(); // Close StyleMap tag
}
-static void kml_output_timestamp(const Waypoint* waypointp)
+void KmlFormat::kml_output_timestamp(const Waypoint* waypointp) const
{
QString time_string = waypointp->CreationTimeXML();
if (!time_string.isEmpty()) {
}
}
-static
-void kml_td(gpsbabel::XmlStreamWriter& hwriter, const QString& boldData, const QString& data)
+void KmlFormat::kml_td(gpsbabel::XmlStreamWriter& hwriter, const QString& boldData, const QString& data)
{
hwriter.writeCharacters(QStringLiteral("\n"));
hwriter.writeStartElement(QStringLiteral("tr"));
hwriter.writeEndElement(); // Close tr tag
}
-static
-void kml_td(gpsbabel::XmlStreamWriter& hwriter, const QString& data)
+void KmlFormat::kml_td(gpsbabel::XmlStreamWriter& hwriter, const QString& data)
{
hwriter.writeCharacters(QStringLiteral("\n"));
hwriter.writeStartElement(QStringLiteral("tr"));
/*
* Output the track summary.
*/
-static
-void kml_output_trkdescription(const route_head* header, const computed_trkdata* td)
+void KmlFormat::kml_output_trkdescription(const route_head* header, const computed_trkdata* td) const
{
if (!td || !trackdata) {
return;
}
-static
-void kml_output_header(const route_head* header, const computed_trkdata* td)
+void KmlFormat::kml_output_header(const route_head* header, const computed_trkdata* td) const
{
- if (!realtime_positioning) {
- writer->writeStartElement(QStringLiteral("Folder"));
- }
+ writer->writeStartElement(QStringLiteral("Folder"));
writer->writeOptionalTextElement(QStringLiteral("name"), header->rte_name);
kml_output_trkdescription(header, td);
}
}
-static
-int kml_altitude_known(const Waypoint* waypoint)
+int KmlFormat::kml_altitude_known(const Waypoint* waypoint) const
{
if (waypoint->altitude == unknown_alt) {
return 0;
return 1;
}
-static
-void kml_write_coordinates(const Waypoint* waypointp)
+void KmlFormat::kml_write_coordinates(const Waypoint* waypointp) const
{
if (kml_altitude_known(waypointp)) {
writer->writeTextElement(QStringLiteral("coordinates"),
/* Rather than a default "top down" view, view from the side to highlight
* topo features.
*/
-static void kml_output_lookat(const Waypoint* waypointp)
+void KmlFormat::kml_output_lookat(const Waypoint* waypointp) const
{
writer->writeStartElement(QStringLiteral("LookAt"));
writer->writeTextElement(QStringLiteral("longitude"), QString::number(waypointp->longitude, 'f', precision));
writer->writeEndElement(); // Close LookAt tag
}
-static void kml_output_positioning(bool tessellate)
+void KmlFormat::kml_output_positioning(bool tessellate) const
{
// These elements must be output as a sequence, i.e. in order.
if (extrude) {
}
/* Output something interesting when we can for route and trackpoints */
-static void kml_output_description(const Waypoint* pt)
+void KmlFormat::kml_output_description(const Waypoint* pt) const
{
const char* alt_units;
writer->writeEndElement(); // Close description tag
}
-static void kml_recompute_time_bounds(const Waypoint* waypointp)
+void KmlFormat::kml_recompute_time_bounds(const Waypoint* waypointp)
{
if (waypointp->GetCreationTime().isValid()) {
if (!(kml_time_min.isValid()) ||
}
}
-static void kml_add_to_bounds(const Waypoint* waypointp)
+void KmlFormat::kml_add_to_bounds(const Waypoint* waypointp)
{
waypt_add_to_bounds(&kml_bounds, waypointp);
kml_recompute_time_bounds(waypointp);
}
-static void kml_output_point(const Waypoint* waypointp, kml_point_type pt_type)
+void KmlFormat::kml_output_point(const Waypoint* waypointp, kml_point_type pt_type) const
{
QString style;
}
}
-static void kml_output_tailer(const route_head* header)
+void KmlFormat::kml_output_tailer(const route_head* header)
{
if (export_points && header->rte_waypt_ct > 0) {
writer->writeEndElement(); // Close Placemark tag
}
- if (!realtime_positioning) {
- writer->writeEndElement(); // Close folder tag
- }
+ writer->writeEndElement(); // Close folder tag
}
/*
*/
// Text that's common to all tabs.
-static
-void kml_gc_all_tabs_text(QString& cdataStr)
+void KmlFormat::kml_gc_all_tabs_text(QString& cdataStr)
{
// cdataStr.append("<a href=\"http://www.geocaching.com\"><img style=\"float: left; padding: 10px\" src=\"http://www.geocaching.com/images/nav/logo_sub.gif\" /> </a>\n");
cdataStr.append("<img align=\"right\" src=\"$[gc_icon]\" />\n");
}
-static const QString map_templates[] = {
- "<a href=\"https://www.google.com/maps?q=$[gc_lat],$[gc_lon]\" target=\"_blank\">Google Maps</a>",
- "<a href=\"http://www.geocaching.com/map/default.aspx?lat=$[gc_lat]&lng=$[gc_lon]\" target=\"_blank\">Geocaching.com Google Map</a>",
- "<a href=\"http://www.mytopo.com/maps.cfm?lat=$[gc_lat]&lon=$[gc_lon]&pid=groundspeak\" target=\"_blank\">MyTopo Maps</a>",
- "<a href=\"http://www.mapquest.com/maps/map.adp?searchtype=address&formtype=latlong&latlongtype=decimal&latitude=$[gc_lat]&longitude=$[gc_lon]&zoom=10\" target=\"_blank\">MapQuest</a>",
- "<a href=\"http://www.bing.com/maps/default.aspx?v=2&sp=point.$[gc_lat]$[gc_lon]\" target=\"_blank\">Bing Maps</a>",
- "<a href=\"http://maps.randmcnally.com/#s=screen&lat=$[gc_lat]&lon=$[gc_lon]&zoom=13&loc1=$[gc_lat],$[gc_lon]\" target=\"_blank\">Rand McNally</a>",
- "<a href=\"http://www.opencyclemap.org/?zoom=12&lat=$[gc_lat]&lon=$[gc_lon]\" target=\"_blank\">Open Cycle Maps</a>",
- "<a href=\"http://www.openstreetmap.org/?mlat=$[gc_lat]&mlon=$[gc_lon]&zoom=12\" target=\"_blank\">Open Street Maps</a>",
+const QString KmlFormat::map_templates[] = {
+ R"(<a href="https://www.google.com/maps?q=$[gc_lat],$[gc_lon]" target="_blank">Google Maps</a>)",
+ R"(<a href="http://www.geocaching.com/map/default.aspx?lat=$[gc_lat]&lng=$[gc_lon]" target="_blank">Geocaching.com Google Map</a>)",
+ R"(<a href="http://www.mytopo.com/maps.cfm?lat=$[gc_lat]&lon=$[gc_lon]&pid=groundspeak" target="_blank">MyTopo Maps</a>)",
+ R"(<a href="http://www.mapquest.com/maps/map.adp?searchtype=address&formtype=latlong&latlongtype=decimal&latitude=$[gc_lat]&longitude=$[gc_lon]&zoom=10" target="_blank">MapQuest</a>)",
+ R"(<a href="http://www.bing.com/maps/default.aspx?v=2&sp=point.$[gc_lat]$[gc_lon]" target="_blank">Bing Maps</a>)",
+ R"(<a href="http://maps.randmcnally.com/#s=screen&lat=$[gc_lat]&lon=$[gc_lon]&zoom=13&loc1=$[gc_lat],$[gc_lon]" target="_blank">Rand McNally</a>)",
+ R"(<a href="http://www.opencyclemap.org/?zoom=12&lat=$[gc_lat]&lon=$[gc_lon]" target="_blank">Open Cycle Maps</a>)",
+ R"(<a href="http://www.openstreetmap.org/?mlat=$[gc_lat]&mlon=$[gc_lon]&zoom=12" target="_blank">Open Street Maps</a>)",
nullptr
};
-
-static
-void kml_gc_make_balloonstyletext()
+void KmlFormat::kml_gc_make_balloonstyletext() const
{
QString cdataStr;
cdataStr.append(" <ul>\n");
// Fortunately, all the mappy map URLs take lat/longs in the URLs, so
// the substitution is easy.
- for (int tp = 0; !map_templates[tp].isEmpty(); tp++) {
+ for (int tp = 0; !map_templates[tp].isEmpty(); ++tp) {
cdataStr.append(" <li>\n");
cdataStr.append(" ");
cdataStr.append(map_templates[tp]);
writer->writeEndElement(); // Close BalloonStyle tag
}
-static
-void kml_gc_make_balloonstyle()
+void KmlFormat::kml_gc_make_balloonstyle() const
{
// For Normal style of gecoaches, scale of label is set to zero
// to make the label invisible. On hover (highlight?) enlarge
writer->writeEndElement(); // Close StyleMap tag
}
-static
-QString
-kml_lookup_gc_icon(const Waypoint* waypointp)
+QString KmlFormat::kml_lookup_gc_icon(const Waypoint* waypointp)
{
const char* icon;
/* This could be done so much better in C99 with designated
return QString("https://www.geocaching.com/images/kml/%1").arg(icon);
}
-static const
-char*
-kml_lookup_gc_container(const Waypoint* waypointp)
+const char* KmlFormat::kml_lookup_gc_container(const Waypoint* waypointp)
{
const char* cont;
return cont;
}
-static QString kml_gc_mkstar(int rating)
+QString KmlFormat::kml_gc_mkstar(int rating)
{
QString star_content;
}
-static QString kml_geocache_get_logs(const Waypoint* wpt)
+QString KmlFormat::kml_geocache_get_logs(const Waypoint* wpt) const
{
QString r;
return r;
}
-static void kml_write_data_element(const QString& name, const QString& value)
+void KmlFormat::kml_write_data_element(const QString& name, const QString& value) const
{
writer->writeStartElement(QStringLiteral("Data"));
writer->writeAttribute(QStringLiteral("name"), name);
writer->writeEndElement(); // Close Data tag
}
-static void kml_write_data_element(const QString& name, const int value)
+void KmlFormat::kml_write_data_element(const QString& name, const int value) const
{
writer->writeStartElement(QStringLiteral("Data"));
writer->writeAttribute(QStringLiteral("name"), name);
writer->writeEndElement(); // Close Data tag
}
-static void kml_write_data_element(const QString& name, const double value)
+void KmlFormat::kml_write_data_element(const QString& name, const double value) const
{
writer->writeStartElement(QStringLiteral("Data"));
writer->writeAttribute(QStringLiteral("name"), name);
writer->writeEndElement(); // Close Data tag
}
-static void kml_write_cdata_element(const QString& name, const QString& value)
+void KmlFormat::kml_write_cdata_element(const QString& name, const QString& value) const
{
writer->writeStartElement(QStringLiteral("Data"));
writer->writeAttribute(QStringLiteral("name"), name);
writer->writeEndElement(); // Close Data tag
}
-static void kml_geocache_pr(const Waypoint* waypointp)
+void KmlFormat::kml_geocache_pr(const Waypoint* waypointp) const
{
const char* issues = "";
* WAYPOINTS
*/
-static void kml_waypt_pr(const Waypoint* waypointp)
+void KmlFormat::kml_waypt_pr(const Waypoint* waypointp) const
{
QString icon;
* TRACKPOINTS
*/
-static void kml_track_hdr(const route_head* header)
+void KmlFormat::kml_track_hdr(const route_head* header) const
{
computed_trkdata td = track_recompute(header);
if (header->rte_waypt_ct > 0 && (export_lines || export_points)) {
}
}
-static void kml_track_disp(const Waypoint* waypointp)
+void KmlFormat::kml_track_disp(const Waypoint* waypointp) const
{
kml_output_point(waypointp, kmlpt_track);
}
-static void kml_track_tlr(const route_head* header)
+void KmlFormat::kml_track_tlr(const route_head* header)
{
if (header->rte_waypt_ct > 0 && (export_lines || export_points)) {
kml_output_tailer(header);
* callback as we have to make multiple passes over the track queues.
*/
-// Helper to write gx:SimpleList, iterating over a route queue and writing out.
-
-enum wp_field {
- fld_cadence,
- fld_depth,
- fld_heartrate,
- fld_temperature,
- fld_power
-};
-
-static void kml_mt_simple_array(const route_head* header,
- const char* name,
- wp_field member)
+void KmlFormat::kml_mt_simple_array(const route_head* header,
+ const char* name,
+ wp_field member) const
{
writer->writeStartElement(QStringLiteral("gx:SimpleArrayData"));
writer->writeAttribute(QStringLiteral("name"), name);
}
// True if at least two points in the track have timestamps.
-static int track_has_time(const route_head* header)
+int KmlFormat::track_has_time(const route_head* header)
{
int points_with_time = 0;
foreach (const Waypoint* tpt, header->waypoint_list) {
}
// Simulate a track_disp_all callback sequence for a single track.
-static void write_as_linestring(const route_head* header)
+void KmlFormat::write_as_linestring(const route_head* header)
{
kml_track_hdr(header);
foreach (const Waypoint* tpt, header->waypoint_list) {
}
-static void kml_mt_hdr(const route_head* header)
+void KmlFormat::kml_mt_hdr(const route_head* header)
{
int has_cadence = 0;
int has_depth = 0;
}
}
-static void kml_mt_tlr(const route_head* header)
+void KmlFormat::kml_mt_tlr(const route_head* header) const
{
if (track_has_time(header)) {
writer->writeEndElement(); // Close gx:Track tag
* ROUTES
*/
-static void kml_route_hdr(const route_head* header)
+void KmlFormat::kml_route_hdr(const route_head* header) const
{
kml_output_header(header, nullptr);
}
-static void kml_route_disp(const Waypoint* waypointp)
+void KmlFormat::kml_route_disp(const Waypoint* waypointp) const
{
kml_output_point(waypointp, kmlpt_route);
}
-static void kml_route_tlr(const route_head* header)
+void KmlFormat::kml_route_tlr(const route_head* header)
{
kml_output_tailer(header);
}
// For Earth 5.0 and later, we write a LookAt that encompasses
// the bounding box of our entire data set and set the event times
// to include all our data.
-static void kml_write_AbstractView()
+void KmlFormat::kml_write_AbstractView()
{
// Make a pass through all the points to find the bounds.
+ auto kml_add_to_bounds_lambda = [this](const Waypoint* waypointp)->void {
+ kml_add_to_bounds(waypointp);
+ };
if (waypt_count()) {
- waypt_disp_all(kml_add_to_bounds);
+ waypt_disp_all(kml_add_to_bounds_lambda);
}
if (track_waypt_count()) {
- track_disp_all(nullptr, nullptr, kml_add_to_bounds);
+ track_disp_all(nullptr, nullptr, kml_add_to_bounds_lambda);
}
if (route_waypt_count()) {
- route_disp_all(nullptr, nullptr, kml_add_to_bounds);
+ route_disp_all(nullptr, nullptr, kml_add_to_bounds_lambda);
}
writer->writeStartElement(QStringLiteral("LookAt"));
// the network position. So we shove the end of the timespan out to
// ensure the right edge of that time slider includes us.
//
- gpsbabel::DateTime time_max;
- time_max = realtime_positioning ? kml_time_max.addSecs(600)
- : kml_time_max;
+ gpsbabel::DateTime time_max = realtime_positioning ? kml_time_max.addSecs(600)
+ : kml_time_max;
writer->writeTextElement(QStringLiteral("end"), time_max.toPrettyString());
}
writer->writeEndElement(); // Close gx:TimeSpan tag
writer->writeEndElement(); // Close LookAt tag
}
-static
-void kml_mt_array_schema(const char* field_name, const char* display_name,
- const char* type)
+void KmlFormat::kml_mt_array_schema(const char* field_name, const char* display_name,
+ const char* type) const
{
writer->writeStartElement(QStringLiteral("gx:SimpleArrayField"));
writer->writeAttribute(QStringLiteral("name"), field_name);
writer->writeEndElement(); // Close gx:SimpleArrayField tag
}
-static void kml_write()
+void KmlFormat::write()
{
const global_trait* traits = get_traits();
if (track_waypt_count()) {
if (trackdirection) {
kml_write_bitmap_style(kmlpt_other, ICON_TRK, "track-none");
- for (int i = 0; i < 16; i++) {
+ for (int i = 0; i < 16; ++i) {
kml_write_bitmap_style(kmlpt_other, QString(ICON_DIR).arg(i), QString("track-%1").arg(i));
}
} else {
writer->writeTextElement(QStringLiteral("name"), QStringLiteral("Waypoints"));
}
- waypt_disp_all(kml_waypt_pr);
+ auto kml_waypt_pr_lambda = [this](const Waypoint* waypointp)->void {
+ kml_waypt_pr(waypointp);
+ };
+ waypt_disp_all(kml_waypt_pr_lambda);
if (!realtime_positioning) {
writer->writeEndElement(); // Close Folder tag
kml_init_color_sequencer(track_count());
if (export_track) {
- track_disp_all(kml_mt_hdr, kml_mt_tlr, nullptr);
+ auto kml_mt_hdr_lambda = [this](const route_head* rte)->void {
+ kml_mt_hdr(rte);
+ };
+ auto kml_mt_tlr_lambda = [this](const route_head* rte)->void {
+ kml_mt_tlr(rte);
+ };
+ track_disp_all(kml_mt_hdr_lambda, kml_mt_tlr_lambda, nullptr);
}
- track_disp_all(kml_track_hdr, kml_track_tlr,
- kml_track_disp);
+ auto kml_track_hdr_lambda = [this](const route_head* rte)->void {
+ kml_track_hdr(rte);
+ };
+ auto kml_track_tlr_lambda = [this](const route_head* rte)->void {
+ kml_track_tlr(rte);
+ };
+ auto kml_track_disp_lambda = [this](const Waypoint* waypointp)->void {
+ kml_track_disp(waypointp);
+ };
+ track_disp_all(kml_track_hdr_lambda, kml_track_tlr_lambda,
+ kml_track_disp_lambda);
if (!realtime_positioning) {
writer->writeEndElement(); // Close Folder tag
writer->writeTextElement(QStringLiteral("name"), QStringLiteral("Routes"));
kml_init_color_sequencer(route_count());
- route_disp_all(kml_route_hdr,
- kml_route_tlr, kml_route_disp);
+ auto kml_route_hdr_lambda = [this](const route_head* rte)->void {
+ kml_route_hdr(rte);
+ };
+ auto kml_route_tlr_lambda = [this](const route_head* rte)->void {
+ kml_route_tlr(rte);
+ };
+ auto kml_route_disp_lambda = [this](const Waypoint* waypointp)->void {
+ kml_route_disp(waypointp);
+ };
+ route_disp_all(kml_route_hdr_lambda,
+ kml_route_tlr_lambda, kml_route_disp_lambda);
writer->writeEndElement(); // Close Folder tag
}
}
/*
* This depends on the table being sorted correctly.
*/
-static const
-char*
-kml_get_posn_icon(int freshness)
-{
- int n_stations = sizeof(kml_tracking_icons) / sizeof(kml_tracking_icons[0]);
-
- for (int i = 0; i < n_stations ; i++) {
- if (freshness >= kml_tracking_icons[i].freshness) {
- return kml_tracking_icons[i].icon;
+QString KmlFormat::kml_get_posn_icon(int freshness)
+{
+ struct kml_tracking_icon {
+ int freshness;
+ QString icon;
+ };
+ static const QVector<kml_tracking_icon> kml_tracking_icons = {
+ { 60, ICON_BASE "youarehere-60.png" }, // Red
+ { 30, ICON_BASE "youarehere-30.png" }, // Yellow
+ { 0, ICON_BASE "youarehere-0.png" }, // Green
+ };
+
+ for (const auto& entry : kml_tracking_icons) {
+ if (freshness >= entry.freshness) {
+ return entry.icon;
}
}
return ICON_NOSAT;
}
-
-static route_head* posn_trk_head = nullptr;
-
-static void
-kml_wr_position(Waypoint* wpt)
+void KmlFormat::wr_position(Waypoint* wpt)
{
static gpsbabel::DateTime last_valid_fix;
- kml_wr_init(posnfilenametmp);
+ wr_init(posnfilenametmp);
if (!posn_trk_head) {
posn_trk_head = new route_head;
+ posn_trk_head->rte_name = "Track";
track_add_head(posn_trk_head);
}
/* In order to avoid clutter while we're sitting still, don't add
track points if we've not moved a minimum distance from the
beginning of our accumulated track. */
- {
+ if (posn_trk_head->waypoint_list.empty()) {
+ track_add_wpt(posn_trk_head, new Waypoint(*wpt));
+ } else {
Waypoint* newest_posn= posn_trk_head->waypoint_list.back();
if (radtometers(gcdist(RAD(wpt->latitude), RAD(wpt->longitude),
}
waypt_add(wpt);
- kml_write();
+ write();
waypt_del(wpt);
/*
track_del_wpt(posn_trk_head, tonuke);
}
- kml_wr_deinit();
+ wr_deinit();
}
-
-ff_vecs_t kml_vecs = {
- ff_type_file,
- FF_CAP_RW_ALL, /* Format can do RW_ALL */
- kml_rd_init,
- kml_wr_init,
- kml_rd_deinit,
- kml_wr_deinit,
- kml_read,
- kml_write,
- nullptr,
- &kml_args,
- CET_CHARSET_UTF8, 1, /* CET-REVIEW */
- { nullptr, nullptr, nullptr, kml_wr_position_init, kml_wr_position, kml_wr_position_deinit },
- nullptr
-};
--- /dev/null
+/*
+ Support for Google Earth & Keyhole "kml" format.
+
+ Copyright (C) 2005-2013 Robert Lipe, robertlipe+source@gpsbabel.org
+ Updates by Andrew Kirmse, akirmse at google.com
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ */
+#ifndef KML_H_INCLUDED_
+#define KML_H_INCLUDED_
+
+#ifdef __WIN32__
+# include <windows.h>
+#endif
+
+#include <tuple> // for tuple, make_tuple, tie
+
+#include <QtCore/QList> // for QList
+#include <QtCore/QString> // for QString, QStringLiteral, operator+, operator!=
+#include <QtCore/QVector> // for QVector
+#include <QtCore/QXmlStreamAttributes> // for QXmlStreamAttributes
+
+#include "defs.h"
+#include "format.h"
+#include "src/core/datetime.h" // for DateTime
+#include "src/core/file.h" // for File
+#include "src/core/xmlstreamwriter.h" // for XmlStreamWriter
+#include "xmlgeneric.h" // for cb_cdata, cb_end, cb_start, xg_callback, xg_string, xg_cb_type, xml_deinit, xml_ignore_tags, xml_init, xml_read, xg_tag_mapping
+
+
+class KmlFormat : public Format
+{
+public:
+ QVector<arglist_t>* get_args() override
+ {
+ return &kml_args;
+ }
+
+ ff_type get_type() const override
+ {
+ return ff_type_file;
+ }
+
+ QVector<ff_cap> get_cap() const override
+ {
+ return FF_CAP_RW_ALL;
+ }
+
+ QString get_encode() const override
+ {
+ return CET_CHARSET_UTF8;
+ }
+
+ int get_fixed_encode() const override
+ {
+ return 1;
+ }
+
+ void rd_init(const QString& fname) override;
+ void read() override;
+ void rd_deinit() override;
+ void wr_init(const QString& fname) override;
+ void write() override;
+ void wr_deinit() override;
+ void wr_position_init(const QString& fname) override;
+ void wr_position(Waypoint* wpt) override;
+ void wr_position_deinit() override;
+
+private:
+ /* Types */
+
+ enum kml_point_type {
+ kmlpt_unknown,
+ kmlpt_waypoint,
+ kmlpt_track,
+ kmlpt_route,
+ kmlpt_multitrack,
+ kmlpt_other
+ };
+
+// Helper to write gx:SimpleList, iterating over a route queue and writing out.
+
+ enum wp_field {
+ fld_cadence,
+ fld_depth,
+ fld_heartrate,
+ fld_temperature,
+ fld_power
+ };
+
+ /* Constants */
+ static constexpr const char* default_precision = "6";
+ static constexpr int kml_color_limit = 204; /* allowed range [0,255] */
+
+ // Multitrack ids to correlate Schema to SchemaData
+ static constexpr const char* kmt_heartrate = "heartrate";
+ static constexpr const char* kmt_cadence = "cadence";
+ static constexpr const char* kmt_temperature = "temperature";
+ static constexpr const char* kmt_depth = "depth";
+ static constexpr const char* kmt_power = "power";
+
+ /* Member Functions */
+
+ void kml_init_color_sequencer(unsigned int steps_per_rev);
+ void kml_step_color();
+ void wpt_s(const QString& args, const QXmlStreamAttributes* attrs);
+ void wpt_e(const QString& args, const QXmlStreamAttributes* attrs);
+ void wpt_name(const QString& args, const QXmlStreamAttributes* attrs);
+ void wpt_desc(const QString& args, const QXmlStreamAttributes* attrs);
+ void wpt_coord(const QString& args, const QXmlStreamAttributes* attrs);
+ void wpt_icon(const QString& args, const QXmlStreamAttributes* attrs);
+ void trk_coord(const QString& args, const QXmlStreamAttributes* attrs);
+ void wpt_time(const QString& args, const QXmlStreamAttributes* attrs);
+ void wpt_ts_begin(const QString& args, const QXmlStreamAttributes* attrs);
+ void wpt_ts_end(const QString& args, const QXmlStreamAttributes* attrs);
+ void gx_trk_s(const QString& args, const QXmlStreamAttributes* attrs);
+ void gx_trk_e(const QString& args, const QXmlStreamAttributes* attrs);
+ void gx_trk_when(const QString& args, const QXmlStreamAttributes* attrs);
+ void gx_trk_coord(const QString& args, const QXmlStreamAttributes* attrs);
+ void kml_output_linestyle(char* color, int width) const;
+ void kml_write_bitmap_style_(const QString& style, const QString& bitmap, int highlighted, int force_heading) const;
+ void kml_write_bitmap_style(kml_point_type pt_type, const QString& bitmap, const QString& customstyle) const;
+ void kml_output_timestamp(const Waypoint* waypointp) const;
+ static void kml_td(gpsbabel::XmlStreamWriter& hwriter, const QString& boldData, const QString& data);
+ static void kml_td(gpsbabel::XmlStreamWriter& hwriter, const QString& data);
+ void kml_output_trkdescription(const route_head* header, const computed_trkdata* td) const;
+ void kml_output_header(const route_head* header, const computed_trkdata* td) const;
+ int kml_altitude_known(const Waypoint* waypoint) const;
+ void kml_write_coordinates(const Waypoint* waypointp) const;
+ void kml_output_lookat(const Waypoint* waypointp) const;
+ void kml_output_positioning(bool tessellate) const;
+ void kml_output_description(const Waypoint* pt) const;
+ void kml_recompute_time_bounds(const Waypoint* waypointp);
+ void kml_add_to_bounds(const Waypoint* waypointp);
+ void kml_output_point(const Waypoint* waypointp, kml_point_type pt_type) const;
+ void kml_output_tailer(const route_head* header);
+ static void kml_gc_all_tabs_text(QString& cdataStr);
+ void kml_gc_make_balloonstyletext() const;
+ void kml_gc_make_balloonstyle() const;
+ static QString kml_lookup_gc_icon(const Waypoint* waypointp);
+ static const char* kml_lookup_gc_container(const Waypoint* waypointp);
+ static QString kml_gc_mkstar(int rating);
+ QString kml_geocache_get_logs(const Waypoint* wpt) const;
+ void kml_write_data_element(const QString& name, const QString& value) const;
+ void kml_write_data_element(const QString& name, int value) const;
+ void kml_write_data_element(const QString& name, double value) const;
+ void kml_write_cdata_element(const QString& name, const QString& value) const;
+ void kml_geocache_pr(const Waypoint* waypointp) const;
+ void kml_waypt_pr(const Waypoint* waypointp) const;
+ void kml_track_hdr(const route_head* header) const;
+ void kml_track_disp(const Waypoint* waypointp) const;
+ void kml_track_tlr(const route_head* header);
+ void kml_mt_simple_array(const route_head* header, const char* name, wp_field member) const;
+ static int track_has_time(const route_head* header);
+ void write_as_linestring(const route_head* header);
+ void kml_mt_hdr(const route_head* header);
+ void kml_mt_tlr(const route_head* header) const;
+ void kml_route_hdr(const route_head* header) const;
+ void kml_route_disp(const Waypoint* waypointp) const;
+ void kml_route_tlr(const route_head* header);
+ void kml_write_AbstractView();
+ void kml_mt_array_schema(const char* field_name, const char* display_name, const char* type) const;
+ static QString kml_get_posn_icon(int freshness);
+
+ /* Data Members */
+
+ // options
+ char* opt_deficon{nullptr};
+ char* opt_export_lines{nullptr};
+ char* opt_export_points{nullptr};
+ char* opt_export_track{nullptr};
+ char* opt_line_width{nullptr};
+ char* opt_line_color{nullptr};
+ char* opt_floating{nullptr};
+ char* opt_extrude{nullptr};
+ char* opt_trackdata{nullptr};
+ char* opt_trackdirection{nullptr};
+ char* opt_units{nullptr};
+ char* opt_labels{nullptr};
+ char* opt_max_position_points{nullptr};
+ char* opt_rotate_colors{nullptr};
+ char* opt_precision{nullptr};
+
+ int export_lines{};
+ int export_points{};
+ int export_track{};
+ int floating{};
+ int extrude{};
+ int trackdata{};
+ int trackdirection{};
+ int max_position_points{};
+ int rotate_colors{};
+ int line_width{};
+ int html_encrypt{};
+ int precision{};
+
+ Waypoint* wpt_tmp{nullptr};
+ bool wpt_tmp_queued{false};
+ QString posnfilename;
+ QString posnfilenametmp;
+
+ route_head* gx_trk_head{nullptr};
+ QList<gpsbabel::DateTime>* gx_trk_times{nullptr};
+ QList<std::tuple<int, double, double, double>>* gx_trk_coords{nullptr};
+
+ gpsbabel::File* oqfile{nullptr};
+ gpsbabel::XmlStreamWriter* writer{nullptr};
+
+ int realtime_positioning{};
+ bounds kml_bounds{};
+ gpsbabel::DateTime kml_time_max;
+ gpsbabel::DateTime kml_time_min;
+
+ QVector<arglist_t> kml_args = {
+ {"deficon", &opt_deficon, "Default icon name", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr },
+ {
+ "lines", &opt_export_lines,
+ "Export linestrings for tracks and routes",
+ "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr,
+ },
+ {
+ "points", &opt_export_points,
+ "Export placemarks for tracks and routes",
+ "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "line_width", &opt_line_width,
+ "Width of lines, in pixels",
+ "6", ARGTYPE_INT, ARG_NOMINMAX, nullptr
+ },
+ {
+ "line_color", &opt_line_color,
+ "Line color, specified in hex AABBGGRR",
+ "99ffac59", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+ },
+ {
+ "floating", &opt_floating,
+ "Altitudes are absolute and not clamped to ground",
+ "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "extrude", &opt_extrude,
+ "Draw extrusion line from trackpoint to ground",
+ "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "track", &opt_export_track,
+ "Write KML track (default = 0)",
+ "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "trackdata", &opt_trackdata,
+ "Include extended data for trackpoints (default = 1)",
+ "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "trackdirection", &opt_trackdirection,
+ "Indicate direction of travel in track icons (default = 0)",
+ "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "units", &opt_units,
+ "Units used when writing comments ('s'tatute, 'm'etric,' 'n'autical, 'a'viation)",
+ "s", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+ },
+ {
+ "labels", &opt_labels,
+ "Display labels on track and routepoints (default = 1)",
+ "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "max_position_points", &opt_max_position_points,
+ "Retain at most this number of position points (0 = unlimited)",
+ "0", ARGTYPE_INT, ARG_NOMINMAX, nullptr
+ },
+ {
+ "rotate_colors", &opt_rotate_colors,
+ "Rotate colors for tracks and routes (default automatic)",
+ nullptr, ARGTYPE_FLOAT, "0", "360", nullptr
+ },
+ {
+ "prec", &opt_precision,
+ "Precision of coordinates, number of decimals",
+ default_precision, ARGTYPE_INT, ARG_NOMINMAX, nullptr
+ },
+ };
+
+ struct {
+ float seq{0.0f};
+ float step{0.0f};
+ gb_color color;
+ } kml_color_sequencer;
+
+ QList<xg_functor_map_entry<KmlFormat>> kml_map = {
+ {&KmlFormat::wpt_s, cb_start, "/Placemark"},
+ {&KmlFormat::wpt_e, cb_end, "/Placemark"},
+ {&KmlFormat::wpt_name, cb_cdata, "/Placemark/name"},
+ {&KmlFormat::wpt_desc, cb_cdata, "/Placemark/description"},
+ {&KmlFormat::wpt_ts_begin, cb_cdata,"/Placemark/TimeSpan/begin"},
+ {&KmlFormat::wpt_ts_end, cb_cdata, "/Placemark/TimeSpan/end"},
+ {&KmlFormat::wpt_time, cb_cdata, "/Placemark/TimeStamp/when"},
+ // Alias for above used in KML 2.0
+ {&KmlFormat::wpt_time, cb_cdata, "/Placemark/TimeInstant/timePosition"},
+ {&KmlFormat::wpt_coord, cb_cdata, "/Placemark/Point/coordinates"},
+ {&KmlFormat::wpt_icon, cb_cdata, "/Placemark/Style/Icon/href"},
+ {&KmlFormat::trk_coord, cb_cdata, "/Placemark/MultiGeometry/LineString/coordinates"},
+ {&KmlFormat::trk_coord, cb_cdata, "/Placemark/GeometryCollection/LineString/coordinates"},
+ {&KmlFormat::trk_coord, cb_cdata, "/Placemark/Polygon/outerBoundaryIs/LinearRing/coordinates"},
+ {&KmlFormat::trk_coord, cb_cdata, "/Placemark/LineString/coordinates"},
+ {&KmlFormat::gx_trk_s, cb_start, "/Placemark/*gx:Track"},
+ {&KmlFormat::gx_trk_e, cb_end, "/Placemark/*gx:Track"},
+ {&KmlFormat::gx_trk_when, cb_cdata, "/Placemark/*gx:Track/when"},
+ {&KmlFormat::gx_trk_coord, cb_cdata, "/Placemark/*gx:Track/gx:coord"},
+ {&KmlFormat::gx_trk_s, cb_start, "/Placemark/Track"}, // KML 2.3
+ {&KmlFormat::gx_trk_e, cb_end, "/Placemark/Track"}, // KML 2.3
+ {&KmlFormat::gx_trk_when, cb_cdata, "/Placemark/Track/when"}, // KML 2.3
+ {&KmlFormat::gx_trk_coord, cb_cdata, "/Placemark/Track/coord"}, // KML 2.3
+ {&KmlFormat::gx_trk_s, cb_start, "/Placemark/MultiTrack/Track"}, // KML 2.3
+ {&KmlFormat::gx_trk_e, cb_end, "/Placemark/MultiTrack/Track"}, // KML 2.3
+ {&KmlFormat::gx_trk_when, cb_cdata, "/Placemark/MultiTrack/Track/when"}, // KML 2.3
+ {&KmlFormat::gx_trk_coord, cb_cdata, "/Placemark/MultiTrack/Track/coord"} // KML 2.3
+ };
+
+ static const char* kml_tags_to_ignore[];
+ static const char* kml_tags_to_skip[];
+
+ // The TimeSpan/begin and TimeSpan/end DateTimes:
+ gpsbabel::DateTime wpt_timespan_begin, wpt_timespan_end;
+
+ static const QString map_templates[];
+
+ route_head* posn_trk_head{nullptr};
+};
+
+#endif // KML_H_INCLUDED_
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
+ <Document>
+ <name>GPS position</name>
+ <LookAt>
+ <gx:TimeSpan>
+ <begin>1970-01-01T00:00:03.464Z</begin>
+ <end>1970-01-01T00:10:29.519Z</end>
+ </gx:TimeSpan>
+ <longitude>-32.056227</longitude>
+ <latitude>30.474664</latitude>
+ <range>1728.780603</range>
+ </LookAt>
+ <!-- Normal track style -->
+ <Style id="track_n">
+ <IconStyle>
+ <scale>.5</scale>
+ <Icon>
+ <href>https://earth.google.com/images/kml-icons/track-directional/track-none.png</href>
+ </Icon>
+ </IconStyle>
+ <LabelStyle>
+ <scale>0</scale>
+ </LabelStyle>
+ </Style>
+ <!-- Highlighted track style -->
+ <Style id="track_h">
+ <IconStyle>
+ <scale>1.2</scale>
+ <Icon>
+ <href>https://earth.google.com/images/kml-icons/track-directional/track-none.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <StyleMap id="track">
+ <Pair>
+ <key>normal</key>
+ <styleUrl>#track_n</styleUrl>
+ </Pair>
+ <Pair>
+ <key>highlight</key>
+ <styleUrl>#track_h</styleUrl>
+ </Pair>
+ </StyleMap>
+ <!-- Normal multiTrack style -->
+ <Style id="multiTrack_n">
+ <IconStyle>
+ <Icon>
+ <href>https://earth.google.com/images/kml-icons/track-directional/track-0.png</href>
+ </Icon>
+ </IconStyle>
+ <LineStyle>
+ <color>99ffac59</color>
+ <width>6</width>
+ </LineStyle>
+ </Style>
+ <!-- Highlighted multiTrack style -->
+ <Style id="multiTrack_h">
+ <IconStyle>
+ <scale>1.2</scale>
+ <Icon>
+ <href>https://earth.google.com/images/kml-icons/track-directional/track-0.png</href>
+ </Icon>
+ </IconStyle>
+ <LineStyle>
+ <color>99ffac59</color>
+ <width>8</width>
+ </LineStyle>
+ </Style>
+ <StyleMap id="multiTrack">
+ <Pair>
+ <key>normal</key>
+ <styleUrl>#multiTrack_n</styleUrl>
+ </Pair>
+ <Pair>
+ <key>highlight</key>
+ <styleUrl>#multiTrack_h</styleUrl>
+ </Pair>
+ </StyleMap>
+ <!-- Normal waypoint style -->
+ <Style id="waypoint_n">
+ <IconStyle>
+ <Icon>
+ <href>https://maps.google.com/mapfiles/kml/pal4/icon61.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <!-- Highlighted waypoint style -->
+ <Style id="waypoint_h">
+ <IconStyle>
+ <scale>1.2</scale>
+ <Icon>
+ <href>https://maps.google.com/mapfiles/kml/pal4/icon61.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <StyleMap id="waypoint">
+ <Pair>
+ <key>normal</key>
+ <styleUrl>#waypoint_n</styleUrl>
+ </Pair>
+ <Pair>
+ <key>highlight</key>
+ <styleUrl>#waypoint_h</styleUrl>
+ </Pair>
+ </StyleMap>
+ <Style id="lineStyle">
+ <LineStyle>
+ <color>99ffac59</color>
+ <width>6</width>
+ </LineStyle>
+ </Style>
+ <Schema id="schema">
+ <gx:SimpleArrayField name="heartrate" type="int">
+ <displayName>Heart Rate</displayName>
+ </gx:SimpleArrayField>
+ <gx:SimpleArrayField name="cadence" type="int">
+ <displayName>Cadence</displayName>
+ </gx:SimpleArrayField>
+ <gx:SimpleArrayField name="temperature" type="float">
+ <displayName>Temperature</displayName>
+ </gx:SimpleArrayField>
+ <gx:SimpleArrayField name="depth" type="float">
+ <displayName>Depth</displayName>
+ </gx:SimpleArrayField>
+ </Schema>
+ <Placemark>
+ <name>Wpt_hCT</name>
+ <snippet/>
+ <description>http://link1.example.com/q31hGd</description>
+ <TimeStamp>
+ <when>1970-01-01T00:00:29.519Z</when>
+ </TimeStamp>
+ <Style>
+ <IconStyle>
+ <Icon>
+ <href>https://earth.google.com/images/kml-icons/youarehere-0.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Point>
+ <coordinates>-32.051141,30.478722</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>Track</name>
+ <styleUrl>#multiTrack</styleUrl>
+ <gx:Track>
+ <when/>
+ <when>1970-01-01T00:00:03.464Z</when>
+ <when>1970-01-01T00:00:04.834Z</when>
+ <when>1970-01-01T00:00:06.126Z</when>
+ <when>1970-01-01T00:00:07.686Z</when>
+ <when>1970-01-01T00:00:09.493Z</when>
+ <when>1970-01-01T00:00:12.434Z</when>
+ <when>1970-01-01T00:00:14.191Z</when>
+ <when>1970-01-01T00:00:16.984Z</when>
+ <when>1970-01-01T00:00:18.913Z</when>
+ <when>1970-01-01T00:00:20.628Z</when>
+ <when>1970-01-01T00:00:22.594Z</when>
+ <when>1970-01-01T00:00:23.968Z</when>
+ <when>1970-01-01T00:00:25.135Z</when>
+ <when>1970-01-01T00:00:26.718Z</when>
+ <when>1970-01-01T00:00:28.139Z</when>
+ <when>1970-01-01T00:00:29.519Z</when>
+ <gx:coord>-32.061312 30.470605 26.03</gx:coord>
+ <gx:coord>-32.060351 30.471588</gx:coord>
+ <gx:coord>-32.059442 30.471933 30.62</gx:coord>
+ <gx:coord>-32.058752 30.472451 75.70</gx:coord>
+ <gx:coord>-32.058143 30.473278</gx:coord>
+ <gx:coord>-32.057275 30.474104 26.70</gx:coord>
+ <gx:coord>-32.056245 30.474413 72.49</gx:coord>
+ <gx:coord>-32.056020 30.475032</gx:coord>
+ <gx:coord>-32.055280 30.475289 57.64</gx:coord>
+ <gx:coord>-32.054461 30.475367 91.16</gx:coord>
+ <gx:coord>-32.054306 30.475838</gx:coord>
+ <gx:coord>-32.053593 30.476512 77.01</gx:coord>
+ <gx:coord>-32.052896 30.476701 2.66</gx:coord>
+ <gx:coord>-32.052293 30.477107 59.30</gx:coord>
+ <gx:coord>-32.051494 30.477113</gx:coord>
+ <gx:coord>-32.051415 30.477953 30.00</gx:coord>
+ <gx:coord>-32.051141 30.478722</gx:coord>
+ <ExtendedData>
+ <SchemaData schemaUrl="#schema">
+ <gx:SimpleArrayData name="cadence">
+ <gx:value>245</gx:value>
+ <gx:value>19</gx:value>
+ <gx:value>227</gx:value>
+ <gx:value>97</gx:value>
+ <gx:value>112</gx:value>
+ <gx:value>142</gx:value>
+ <gx:value>222</gx:value>
+ <gx:value>130</gx:value>
+ <gx:value>142</gx:value>
+ <gx:value>118</gx:value>
+ <gx:value>64</gx:value>
+ <gx:value>0</gx:value>
+ <gx:value>186</gx:value>
+ <gx:value>155</gx:value>
+ <gx:value>210</gx:value>
+ <gx:value>0</gx:value>
+ <gx:value>0</gx:value>
+ </gx:SimpleArrayData>
+ <gx:SimpleArrayData name="depth">
+ <gx:value>0.0</gx:value>
+ <gx:value>0.0</gx:value>
+ <gx:value>162.6</gx:value>
+ <gx:value>0.0</gx:value>
+ <gx:value>170.7</gx:value>
+ <gx:value>0.0</gx:value>
+ <gx:value>421.8</gx:value>
+ <gx:value>830.1</gx:value>
+ <gx:value>218.1</gx:value>
+ <gx:value>292.2</gx:value>
+ <gx:value>426.2</gx:value>
+ <gx:value>0.0</gx:value>
+ <gx:value>911.3</gx:value>
+ <gx:value>174.5</gx:value>
+ <gx:value>804.5</gx:value>
+ <gx:value>52.5</gx:value>
+ <gx:value>640.0</gx:value>
+ </gx:SimpleArrayData>
+ <gx:SimpleArrayData name="heartrate">
+ <gx:value>25</gx:value>
+ <gx:value>0</gx:value>
+ <gx:value>41</gx:value>
+ <gx:value>244</gx:value>
+ <gx:value>250</gx:value>
+ <gx:value>253</gx:value>
+ <gx:value>33</gx:value>
+ <gx:value>194</gx:value>
+ <gx:value>238</gx:value>
+ <gx:value>0</gx:value>
+ <gx:value>227</gx:value>
+ <gx:value>164</gx:value>
+ <gx:value>246</gx:value>
+ <gx:value>52</gx:value>
+ <gx:value>90</gx:value>
+ <gx:value>53</gx:value>
+ <gx:value>96</gx:value>
+ </gx:SimpleArrayData>
+ <gx:SimpleArrayData name="temperature">
+ <gx:value>0.0</gx:value>
+ <gx:value>17.8</gx:value>
+ <gx:value>4.4</gx:value>
+ <gx:value>12.7</gx:value>
+ <gx:value>0.0</gx:value>
+ <gx:value>0.0</gx:value>
+ <gx:value>2.2</gx:value>
+ <gx:value>7.9</gx:value>
+ <gx:value>4.7</gx:value>
+ <gx:value>31.9</gx:value>
+ <gx:value>0.0</gx:value>
+ <gx:value>24.3</gx:value>
+ <gx:value>23.2</gx:value>
+ <gx:value>28.0</gx:value>
+ <gx:value>21.8</gx:value>
+ <gx:value>0.0</gx:value>
+ <gx:value>0.0</gx:value>
+ </gx:SimpleArrayData>
+ </SchemaData>
+ </ExtendedData>
+ </gx:Track>
+ </Placemark>
+ <Folder>
+ <name>Track</name>
+ <snippet/>
+ <description>
+<![CDATA[<table>
+<tr><td><b>Distance</b> 4761.1 ft </td></tr>
+<tr><td><b>Min Alt</b> 8.740 ft </td></tr>
+<tr><td><b>Max Alt</b> 299.085 ft </td></tr>
+<tr><td><b>Min Speed</b> 57.9 mph </td></tr>
+<tr><td><b>Max Speed</b> 156.4 mph </td></tr>
+<tr><td><b>Avg Speed</b> 124.6 mph </td></tr>
+<tr><td><b>Avg Heart Rate</b> 147.1 bpm </td></tr>
+<tr><td><b>Min Heart Rate</b> 25 bpm </td></tr>
+<tr><td><b>Max Heart Rate</b> 253 bpm </td></tr>
+<tr><td><b>Avg Cadence</b> 147.8 rpm </td></tr>
+<tr><td><b>Max Cadence</b> 245 rpm </td></tr>
+<tr><td><b>Start Time</b>1970-01-01T00:00:03.464Z</td></tr>
+<tr><td><b>End Time</b>1970-01-01T00:00:29.519Z</td></tr>
+</table>]]>
+</description>
+ <TimeSpan>
+ <begin>1970-01-01T00:00:03.464Z</begin>
+ <end>1970-01-01T00:00:29.519Z</end>
+ </TimeSpan>
+ <Folder>
+ <name>Points</name>
+ <Placemark>
+ <name>Wpt_QB</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.061312 </td></tr>
+<tr><td>Latitude: 30.470605 </td></tr>
+<tr><td>Altitude: 85.400 ft </td></tr>
+<tr><td>Heart rate: 25 </td></tr>
+<tr><td>Cadence: 245 </td></tr>
+<tr><td>Heading: 317.9 </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.061312</longitude>
+ <latitude>30.470605</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.061312,30.470605,26.03</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>Wpt_Y8GPuG</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.060351 </td></tr>
+<tr><td>Latitude: 30.471588 </td></tr>
+<tr><td>Cadence: 19 </td></tr>
+<tr><td>Temperature: 17.8 </td></tr>
+<tr><td>Speed: 146.2 mph </td></tr>
+<tr><td>Heading: 40.1 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:03.464Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.060351</longitude>
+ <latitude>30.471588</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:03.464Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.060351,30.471588</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>Wpt_hTiV</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.059442 </td></tr>
+<tr><td>Latitude: 30.471933 </td></tr>
+<tr><td>Altitude: 100.458 ft </td></tr>
+<tr><td>Heart rate: 41 </td></tr>
+<tr><td>Cadence: 227 </td></tr>
+<tr><td>Temperature: 4.4 </td></tr>
+<tr><td>Depth: 533.4 ft </td></tr>
+<tr><td>Speed: 155.7 mph </td></tr>
+<tr><td>Heading: 66.3 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:04.834Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.059442</longitude>
+ <latitude>30.471933</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:04.834Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.059442,30.471933,30.62</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>Wpt_Fr0VTZa</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.058752 </td></tr>
+<tr><td>Latitude: 30.472451 </td></tr>
+<tr><td>Altitude: 248.355 ft </td></tr>
+<tr><td>Heart rate: 244 </td></tr>
+<tr><td>Cadence: 97 </td></tr>
+<tr><td>Temperature: 12.7 </td></tr>
+<tr><td>Speed: 152.0 mph </td></tr>
+<tr><td>Heading: 48.9 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:06.126Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.058752</longitude>
+ <latitude>30.472451</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:06.126Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.058752,30.472451,75.70</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>Wpt_8f</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.058143 </td></tr>
+<tr><td>Latitude: 30.473278 </td></tr>
+<tr><td>Heart rate: 250 </td></tr>
+<tr><td>Cadence: 112 </td></tr>
+<tr><td>Depth: 560.0 ft </td></tr>
+<tr><td>Speed: 156.4 mph </td></tr>
+<tr><td>Heading: 32.4 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:07.686Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.058143</longitude>
+ <latitude>30.473278</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:07.686Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.058143,30.473278</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>Wpt_R</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.057275 </td></tr>
+<tr><td>Latitude: 30.474104 </td></tr>
+<tr><td>Altitude: 87.606 ft </td></tr>
+<tr><td>Heart rate: 253 </td></tr>
+<tr><td>Cadence: 142 </td></tr>
+<tr><td>Speed: 153.6 mph </td></tr>
+<tr><td>Heading: 42.2 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:09.493Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.057275</longitude>
+ <latitude>30.474104</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:09.493Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.057275,30.474104,26.70</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>ESTIMATED Position</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.056245 </td></tr>
+<tr><td>Latitude: 30.474413 </td></tr>
+<tr><td>Altitude: 237.843 ft </td></tr>
+<tr><td>Heart rate: 33 </td></tr>
+<tr><td>Cadence: 222 </td></tr>
+<tr><td>Temperature: 2.2 </td></tr>
+<tr><td>Depth: 1383.8 ft </td></tr>
+<tr><td>Speed: 83.3 mph </td></tr>
+<tr><td>Heading: 70.8 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:12.434Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.056245</longitude>
+ <latitude>30.474413</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:12.434Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.056245,30.474413,72.49</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>Wpt_8JwVPYQ</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.056020 </td></tr>
+<tr><td>Latitude: 30.475032 </td></tr>
+<tr><td>Heart rate: 194 </td></tr>
+<tr><td>Cadence: 130 </td></tr>
+<tr><td>Temperature: 7.9 </td></tr>
+<tr><td>Depth: 2723.3 ft </td></tr>
+<tr><td>Speed: 91.8 mph </td></tr>
+<tr><td>Heading: 17.4 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:14.191Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.056020</longitude>
+ <latitude>30.475032</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:14.191Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.056020,30.475032</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>Wpt_e</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.055280 </td></tr>
+<tr><td>Latitude: 30.475289 </td></tr>
+<tr><td>Altitude: 189.100 ft </td></tr>
+<tr><td>Heart rate: 238 </td></tr>
+<tr><td>Cadence: 142 </td></tr>
+<tr><td>Temperature: 4.7 </td></tr>
+<tr><td>Depth: 715.4 ft </td></tr>
+<tr><td>Speed: 57.9 mph </td></tr>
+<tr><td>Heading: 68.0 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:16.984Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.055280</longitude>
+ <latitude>30.475289</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:16.984Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.055280,30.475289,57.64</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>ESTIMATED Position</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.054461 </td></tr>
+<tr><td>Latitude: 30.475367 </td></tr>
+<tr><td>Altitude: 299.085 ft </td></tr>
+<tr><td>Cadence: 118 </td></tr>
+<tr><td>Temperature: 31.9 </td></tr>
+<tr><td>Depth: 958.6 ft </td></tr>
+<tr><td>Speed: 91.8 mph </td></tr>
+<tr><td>Heading: 83.7 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:18.913Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.054461</longitude>
+ <latitude>30.475367</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:18.913Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.054461,30.475367,91.16</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>ESTIMATED Position</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.054306 </td></tr>
+<tr><td>Latitude: 30.475838 </td></tr>
+<tr><td>Heart rate: 227 </td></tr>
+<tr><td>Cadence: 64 </td></tr>
+<tr><td>Depth: 1398.4 ft </td></tr>
+<tr><td>Speed: 71.0 mph </td></tr>
+<tr><td>Heading: 15.8 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:20.628Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.054306</longitude>
+ <latitude>30.475838</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:20.628Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.054306,30.475838</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>Wpt_4</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.053593 </td></tr>
+<tr><td>Latitude: 30.476512 </td></tr>
+<tr><td>Altitude: 252.661 ft </td></tr>
+<tr><td>Heart rate: 164 </td></tr>
+<tr><td>Temperature: 24.3 </td></tr>
+<tr><td>Speed: 115.5 mph </td></tr>
+<tr><td>Heading: 42.4 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:22.594Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.053593</longitude>
+ <latitude>30.476512</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:22.594Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.053593,30.476512,77.01</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>Wpt_25dSc2Mb</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.052896 </td></tr>
+<tr><td>Latitude: 30.476701 </td></tr>
+<tr><td>Altitude: 8.740 ft </td></tr>
+<tr><td>Heart rate: 246 </td></tr>
+<tr><td>Cadence: 186 </td></tr>
+<tr><td>Temperature: 23.2 </td></tr>
+<tr><td>Depth: 2989.8 ft </td></tr>
+<tr><td>Speed: 114.1 mph </td></tr>
+<tr><td>Heading: 72.5 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:23.968Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.052896</longitude>
+ <latitude>30.476701</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:23.968Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.052896,30.476701,2.66</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>Wpt_iHp8</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.052293 </td></tr>
+<tr><td>Latitude: 30.477107 </td></tr>
+<tr><td>Altitude: 194.545 ft </td></tr>
+<tr><td>Heart rate: 52 </td></tr>
+<tr><td>Cadence: 155 </td></tr>
+<tr><td>Temperature: 28.0 </td></tr>
+<tr><td>Depth: 572.3 ft </td></tr>
+<tr><td>Speed: 140.7 mph </td></tr>
+<tr><td>Heading: 52.0 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:25.135Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.052293</longitude>
+ <latitude>30.477107</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:25.135Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.052293,30.477107,59.30</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>Wpt_lFMiR</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.051494 </td></tr>
+<tr><td>Latitude: 30.477113 </td></tr>
+<tr><td>Heart rate: 90 </td></tr>
+<tr><td>Cadence: 210 </td></tr>
+<tr><td>Temperature: 21.8 </td></tr>
+<tr><td>Depth: 2639.6 ft </td></tr>
+<tr><td>Speed: 108.3 mph </td></tr>
+<tr><td>Heading: 89.5 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:26.718Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.051494</longitude>
+ <latitude>30.477113</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:26.718Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.051494,30.477113</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>Wpt_k2lz15k</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.051415 </td></tr>
+<tr><td>Latitude: 30.477953 </td></tr>
+<tr><td>Altitude: 98.438 ft </td></tr>
+<tr><td>Heart rate: 53 </td></tr>
+<tr><td>Depth: 172.3 ft </td></tr>
+<tr><td>Speed: 147.6 mph </td></tr>
+<tr><td>Heading: 4.6 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:28.139Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.051415</longitude>
+ <latitude>30.477953</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:28.139Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.051415,30.477953,30.00</coordinates>
+ </Point>
+ </Placemark>
+ <Placemark>
+ <name>Wpt_hCT</name>
+ <snippet/>
+ <description><![CDATA[
+<table>
+<tr><td>Longitude: -32.051141 </td></tr>
+<tr><td>Latitude: 30.478722 </td></tr>
+<tr><td>Heart rate: 96 </td></tr>
+<tr><td>Depth: 2099.9 ft </td></tr>
+<tr><td>Speed: 145.1 mph </td></tr>
+<tr><td>Heading: 17.1 </td></tr>
+<tr><td>Time: 1970-01-01T00:00:29.519Z </td></tr>
+</table>
+]]></description>
+ <LookAt>
+ <longitude>-32.051141</longitude>
+ <latitude>30.478722</latitude>
+ <tilt>66</tilt>
+ </LookAt>
+ <TimeStamp>
+ <when>1970-01-01T00:00:29.519Z</when>
+ </TimeStamp>
+ <styleUrl>#track</styleUrl>
+ <Point>
+ <coordinates>-32.051141,30.478722</coordinates>
+ </Point>
+ </Placemark>
+ </Folder>
+ <Placemark>
+ <name>Path</name>
+ <styleUrl>#lineStyle</styleUrl>
+ <LineString>
+ <tessellate>1</tessellate>
+ <coordinates>
+-32.061312,30.470605,26.03
+-32.060351,30.471588
+-32.059442,30.471933,30.62
+-32.058752,30.472451,75.70
+-32.058143,30.473278
+-32.057275,30.474104,26.70
+-32.056245,30.474413,72.49
+-32.056020,30.475032
+-32.055280,30.475289,57.64
+-32.054461,30.475367,91.16
+-32.054306,30.475838
+-32.053593,30.476512,77.01
+-32.052896,30.476701,2.66
+-32.052293,30.477107,59.30
+-32.051494,30.477113
+-32.051415,30.477953,30.00
+-32.051141,30.478722
+</coordinates>
+ </LineString>
+ </Placemark>
+ </Folder>
+ </Document>
+</kml>
gpsbabel -i kml -f ${REFERENCE}/track/Placemark-Track-1.kml -o gpx -F ${TMPDIR}/Placemark-Track-1~kml.gpx
compare ${REFERENCE}/track/Placemark-Track-1~kml.gpx ${TMPDIR}/Placemark-Track-1~kml.gpx
+# kml realtime writer
+gpsbabel -T -i random,points=20,seed=33,nodelay -f dummy -o kml,track -F ${TMPDIR}/realtime.kml
+compare ${REFERENCE}/realtime.kml ${TMPDIR}/realtime.kml
+
if [ "${RUNNINGVALGRIND}" != "0" ]; then
set -e
if which xmllint > /dev/null;
#include "ggv_bin.h"
#include "globalsat_sport.h"
#include "gpx.h"
+#include "kml.h"
#include "legacyformat.h"
#include "lowranceusr.h"
#include "mynav.h"
-#include "qstarz_bl_1000.h"
#include "nmea.h"
#include "qstarz_bl_1000.h"
#include "random.h"
extern ff_vecs_t mps_vecs;
extern ff_vecs_t ozi_vecs;
extern ff_vecs_t pcx_vecs;
-extern ff_vecs_t kml_vecs;
#if MAXIMAL_ENABLED
extern ff_vecs_t gpsutil_vecs;
extern ff_vecs_t holux_vecs;
NmeaFormat nmea_fmt;
LegacyFormat ozi_fmt {ozi_vecs};
LegacyFormat pcx_fmt {pcx_vecs};
- LegacyFormat kml_fmt {kml_vecs};
+ KmlFormat kml_fmt;
#if MAXIMAL_ENABLED
LegacyFormat gpsutil_fmt {gpsutil_vecs};
LowranceusrFormat lowranceusr_fmt;